package org.dfg.corejava.jdk6.jaxb2;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;

import org.w3c.dom.Node;

/**
 * xml生成解析
 * @author DingFugui
 */
public class Jaxb2Test {
	public static void main(String[] args) throws JAXBException, IOException {
		writer();
		// read();
	}

	private static void read() throws JAXBException {
		JAXBContext context = JAXBContext.newInstance(Persons.class);
		Unmarshaller m = context.createUnmarshaller();
		Persons ps = (Persons) m.unmarshal(new File("C:/person.xml"));
		// System.out.println(ps.getList());
	}

	public static void writer() throws JAXBException, IOException {
		JAXBContext context = JAXBContext.newInstance(Persons.class);
		Marshaller m = context.createMarshaller();
		m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
		m.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
		// m.setProperty(Marshaller.JAXB_NO_NAMESPACE_SCHEMA_LOCATION, "aaa");
		// m.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, "bb");
		m.setProperty(Marshaller.JAXB_FRAGMENT, false);// 如果为ture，会没有头

		Adress a = new Adress("山东", "济南");
		Person p = new Person("qq", a);
		List<Person> list = new ArrayList<>();
		list.add(p);
		Persons ps = new Persons();

		Map<String, String> params = new HashMap<String, String>();
		params.put("q", "1");
		params.put("w", "2");

		ps.setPersons(list);
		ps.setParams(params);

		// FileWriter out = new FileWriter(new File("c:/person.xml"));
		StringWriter out = new StringWriter();

		m.marshal(ps, out);

		System.out.println(out.toString());
		out.close();
	}
}

@XmlAccessorType(XmlAccessType.FIELD)
// 加入此注解，可以解决属性名与get方法重复问题
@XmlType(name = "", propOrder = { "person", "params" })
@XmlRootElement(name = "list")
class Persons {
	public Persons() {
	}

	@XmlElement(required = true)
	private List<Person> person;

	private Map<String, String> params;

	public void setPersons(List<Person> person) {
		this.person = person;
	}

	/*
	 * 经测试，@XmlElement可以加在属性或者get方法上，api会根据目标推断生成的节点名字 。
	 * 如果加在属性上，再生成标准的get方法，会报错，只能修改get方法名字，这会导致不规范。
	 * 如果加在方法上，需要修改属性名，虽然还是不规范，但是对于外部没有影响
	 */
	public List<Person> getPerson() {
		return person;
	}

	public void setPerson(List<Person> person) {
		this.person = person;
	}

	// @XmlJavaTypeAdapter(MapAdapter.class)

	public Map<String, String> getParams() {
		return params;
	}

	public void setParams(Map<String, String> params) {
		this.params = params;
	}

}

class Person {
	@XmlAttribute
	private String name;
	@XmlElement
	private Adress adress;

	public Person() {
	}

	public Person(String name, Adress adress) {
		this.name = name;
		this.adress = adress;
	}

	public void setName(String name) {
		this.name = name;
	}

	public void setAdress(Adress adress) {
		this.adress = adress;
	}

	@Override
	public String toString() {
		return name + "~" + adress;
	}
}

class Adress {
	@XmlAttribute
	private String area;
	@XmlElement
	private String city;

	public Adress() {

	}

	public Adress(String area, String city) {
		super();
		this.area = area;
		this.city = city;
	}

	public void setArea(String area) {
		this.area = area;
	}

	public void setCity(String city) {
		this.city = city;
	}

	@Override
	public String toString() {
		return area + ":" + city;
	}
}
